package id.mankel.commons.util;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

/**
 * TIME ZONE: 西 -12, -11, -10, ..., -1, 0, 1, ..., 10, 11, 12 东
 *
 * @author Mankel
 * @see LocalDateTime#format(DateTimeFormatter)
 * @see LocalDateTime#parse(CharSequence, DateTimeFormatter)
 * @see java.time.temporal.ChronoUnit
 * @see java.time.Duration
 * @see java.time.Period
 */
public class MkDates {

    /**
     * 默认时区偏移量（小时）
     */
    public static final int DEFAULT_TIME_ZONE_OFFSET_IN_HOUR = 8;
    /**
     * 默认时区偏移量（分）
     */
    public static final int DEFAULT_TIME_ZONE_OFFSET_IN_MINUTE = DEFAULT_TIME_ZONE_OFFSET_IN_HOUR * 60;
    /**
     * 默认时区偏移量（秒）
     */
    public static final int DEFAULT_TIME_ZONE_OFFSET_IN_SECOND = DEFAULT_TIME_ZONE_OFFSET_IN_MINUTE * 60;

    /**
     * Default time zone offset: 8.
     */
    public static final ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.ofHours(DEFAULT_TIME_ZONE_OFFSET_IN_HOUR);

    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static final DateTimeFormatter YYYY_MM_DD_HH_MM_SS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * yyyy-MM-dd
     */
    public static final DateTimeFormatter YYYY_MM_DD = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * Returns true if seconds between timestamp and now is within specific seconds.
     *
     * @param timestamp
     * @param timeZoneOffset
     * @param seconds
     * @return
     */
    public static boolean isWithinSeconds(String timestamp, int timeZoneOffset, int seconds) {
        LocalDateTime dt = clientToServer(LocalDateTime.parse(timestamp, YYYY_MM_DD_HH_MM_SS), timeZoneOffset);
        return seconds >= ChronoUnit.SECONDS.between(dt, LocalDateTime.now());
    }

    public static LocalDateTime serverToClient(LocalDateTime serverDateTime, int clientTimeZoneOffset) {
        return changeTimeZone(serverDateTime, DEFAULT_ZONE_OFFSET, ZoneOffset.ofTotalSeconds(clientTimeZoneOffset * 60));
    }

    /**
     * Transforms client date time to server date time using client timestamp and client time zone offset.
     *
     * @param clientDateTime date time from client
     * @param clientTimeZoneOffset time zone offset from client, in minutes
     * @return server date time
     */
    public static LocalDateTime clientToServer(LocalDateTime clientDateTime, int clientTimeZoneOffset) {
        return changeTimeZone(clientDateTime, ZoneOffset.ofTotalSeconds(clientTimeZoneOffset * 60), DEFAULT_ZONE_OFFSET);
    }



    // ==================================================
    // private


    /**
     * Changes the date time's time zone offset from <b>from</b> to <b>to</b>.
     *
     * @param datetime date time to be changed
     * @param from from ZoneOffset
     * @param to to ZoneOffset
     * @return
     */
    private static LocalDateTime changeTimeZone(LocalDateTime datetime, ZoneOffset from, ZoneOffset to) {
        return datetime.atOffset(from).withOffsetSameInstant(to).toLocalDateTime();
    }

}
